﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management;
using System.Net.NetworkInformation;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using static System.Net.Mime.MediaTypeNames;

namespace IPCPages
{
    public class RegCodeCheck
    {
        /// <summary>
        /// 取本机机器码
        /// </summary>
        public static string GetMachineCode()
        {
            //CPU信息
            string cpuInfo = GetMD5Value(GetCpuID() + typeof(string).ToString());
            if (cpuInfo.Equals("UnknowCpuInfo")) return null;
            //磁盘信息
            //string diskInfo = GetMD5Value(GetDiskID() + typeof(int).ToString());
            //if (diskInfo.Equals("UnknowDiskInfo")) return null;
            //MAC地址
            string macInfo = GetMD5Value(GetMacByNetworkInterface() + typeof(double).ToString());
            if (macInfo.Equals("UnknowMacInfo")) return null;
            //返回机器码
            string machineCode =  GetNum(cpuInfo, 5) + GetNum(macInfo, 5); // + GetNum(diskInfo, 8)
            if (machineCode.Length > 14)
            {
                return machineCode.Substring(14);
            }
            else
            {
                return machineCode;
            }
        }

        /// <summary>
        /// 取MD5
        /// </summary>
        /// <param name="value">要加密的字符串</param>
        public static string GetMD5Value(string value)
        {
            byte[] buffer = System.Text.Encoding.Default.GetBytes(value);
            try
            {
                System.Security.Cryptography.MD5CryptoServiceProvider check;
                check = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] somme = check.ComputeHash(buffer);
                string ret = "";
                foreach (byte a in somme)
                {
                    if (a < 16)
                        ret += "0" + a.ToString("X");
                    else
                        ret += a.ToString("X");
                }
                return ret.ToLower();
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// 取数字
        /// </summary>
        /// <param name="md5"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static string GetNum(string md5, int len)
        {
            Regex regex = new Regex(@"\d");
            MatchCollection listMatch = regex.Matches(md5);
            string str = "";
            for (int i = 0; i < len; i++)
            {
                str += listMatch[i].Value;
            }
            while (str.Length < len)
            {
                //不足补0
                str += "0";
            }
            return str;
        }

        /// <summary>
        /// 取CPU序列号
        /// </summary>
        public static string GetCpuID()
        {
            try
            {
                string cpuInfo = "";
                ManagementClass mc = new ManagementClass("Win32_Processor");
                ManagementObjectCollection moc = mc.GetInstances();
                foreach (ManagementObject mo in moc)
                {
                    cpuInfo = mo.Properties["ProcessorId"].Value.ToString();
                }
                moc.Dispose();
                mc.Dispose();
                return cpuInfo;
            }
            catch
            {
                return "UnknowCpuInfo";
            }
        }

        /// <summary>
        /// 取硬盘序列号
        /// </summary>
        public static string GetDiskID()
        {
            try
            {
                string HDid = "";
                ManagementClass mc = new ManagementClass("Win32_DiskDrive");
                ManagementObjectCollection moc = mc.GetInstances();
                foreach (ManagementObject mo in moc)
                {
                    HDid = (string)mo.Properties["Model"].Value;
                }
                moc.Dispose();
                mc.Dispose();
                return HDid;
            }
            catch
            {
                return "UnknowDiskInfo";
            }
        }

        /// <summary>
        /// 获取本机MAC地址
        /// </summary>
        public static string GetMacByNetworkInterface()
        {
            try
            {
                NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
                foreach (NetworkInterface ni in interfaces)
                {
                    return BitConverter.ToString(ni.GetPhysicalAddress().GetAddressBytes());
                }
                return "UnknowMacInfo";
            }
            catch (Exception)
            {
                return "UnknowMacInfo";
            }
        }

        //加密key
        public static string machineCodeEncryptKey = "9832";

        /// <summary>
        /// 根据机器码产生注册码
        /// </summary>
        /// <param name="machineCode">机器码</param>
        /// <param name="overTime">到期时间</param>
        /// <returns>注册码</returns>
        public static string CreateRegisterCode(string machineCode, DateTime overTime)
        {
            //格式：机器码&过期时间&注册时间
            var finalCode = machineCode + "&" + overTime.ToString("s") + "&" + DateTime.Now.ToString("s");
            //加密
            return ToEncryptString(machineCodeEncryptKey, finalCode);
        }

        /// <summary>
        /// 字符串加密
        /// </summary>
        /// <param name="key">加密key</param>
        /// <param name="str">要加密的字符串</param>
        public static string ToEncryptString(string key, string str)
        {
            try
            {
                //将密钥字符串转换为字节序列
                var P_byte_key = Encoding.Unicode.GetBytes(key);
                //将字符串转换为字节序列
                var P_byte_data = Encoding.Unicode.GetBytes(str);
                //创建内存流对象
                MemoryStream mStream = new MemoryStream();
                {
                    using (CryptoStream P_CryptStream_Stream = new CryptoStream(mStream, new DESCryptoServiceProvider().CreateEncryptor(P_byte_key, P_byte_key), CryptoStreamMode.Write))
                    {
                        //向加密流中写入字节序列
                        P_CryptStream_Stream.Write(P_byte_data, 0, P_byte_data.Length);
                        //将数据压入基础流
                        P_CryptStream_Stream.FlushFinalBlock();
                        //从内存流中获取字节序列
                        var res = mStream.ToArray();
                        P_CryptStream_Stream.Dispose();
                        mStream.Dispose();
                        return Convert.ToBase64String(res);
                    }
                }
            }
            catch (CryptographicException ce)
            {
                throw new Exception(ce.Message);
            }
        }


        //加密key
        //public static string machineCodeEncryptKey = "9832";

        /// <summary>
        /// 检查注册码（校验本地机器码）
        /// </summary>
        /// <param name="registerCode">注册码</param>
        /// <param name="overTime">返回过期时间</param>
        /// <param name="registerTime">返回注册时间</param>
        /// <returns>机器码与注册码匹配结果</returns>
        public static bool CheckRegister(string registerCode, ref DateTime overTime, ref DateTime registerTime)
        {
            try
            {
                var finalCodeList = ToDecryptString(machineCodeEncryptKey, registerCode).Split('&');
                if (finalCodeList.Length == 3)
                {
                    DateTime.TryParse(finalCodeList[1], out overTime);
                    DateTime.TryParse(finalCodeList[2], out registerTime);
                    //获取本地机器码
                    var machineCode = GetMachineCode();
                    return machineCode != null && (finalCodeList[0] == machineCode);
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 字符串解密
        /// </summary>
        /// <param name="key">加密key</param>
        /// <param name="str">要解密的字符串</param>
        public static string ToDecryptString(string key, string str)
        {
            try
            {
                //将密钥字符串转换为字节序列
                var P_byte_key = Encoding.Unicode.GetBytes(key);
                //将加密后的字符串转换为字节序列
                var P_byte_data = Convert.FromBase64String(str);
                //创建内存流对象并写入数据,创建加密流对象
                CryptoStream cStream = new CryptoStream(new MemoryStream(P_byte_data), new DESCryptoServiceProvider().CreateDecryptor(P_byte_key, P_byte_key), CryptoStreamMode.Read);
                //创建字节序列对象
                var tempDate = new byte[200];
                //创建内存流对象
                MemoryStream mStream = new MemoryStream();
                //创建记数器
                int i = 0;
                //使用while循环得到解密数据
                while ((i = cStream.Read(tempDate, 0, tempDate.Length)) > 0)
                {
                    //将解密后的数据放入内存流
                    mStream.Write(tempDate, 0, i);
                }
                var res = Encoding.Unicode.GetString(mStream.ToArray());
                mStream.Dispose();
                cStream.Dispose();
                return res;
            }
            catch (CryptographicException ce)
            {
                throw new Exception(ce.Message);
            }
        }

        public static bool CheckRegCode(string regCode, ref string machineCode)
        {
            //获取机器码
            if (string.IsNullOrEmpty(machineCode))
                machineCode = GetMachineCode();
            string base64 = Convert.ToBase64String(System.Text.Encoding.Default.GetBytes("ysl"+machineCode));
            string md5 = GetMD5Value(base64);
            //后10位比较
            string md5_1 = md5.Substring(0, 10).ToUpper();
            string md5_2 = regCode.ToUpper();
            if (md5_1 == md5_2)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}
